/*
 *  vovkulaka - printer management
 *
 *  Copyright (C) 2011 by Volodymyr M. Shcherbyna <volodymyr@shcherbyna.com>
 *
 *	This file is part of vovkulaka.
 *
 *  vovkulaka is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  vovkulaka is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with vovkulaka.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "printersmanagement.h"

/**   C'tor of the object

    * @return initialized object
*/
CPrintersManagement::CPrintersManagement(CConfiguration & c) : m_config(c)
{
	
}

/**   D'tor of the object

    * @return de-initialized object
*/
CPrintersManagement::~CPrintersManagement(void)
{
}

/**   Enumerating currently installed printer(s)

    * @return boolean
*/
bool CPrintersManagement::EnumAllPrinters()
{
	PRINTER_INFO_2 *pPrinterInfo = NULL;

	DWORD	dwSize			= 0,
			dwSizeNeeded	= 0,
			ppInfoReturned	= 0;

	bool	bRetVal			= false;

lbl_retry:

	if (EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pPrinterInfo, dwSize, &dwSizeNeeded, &ppInfoReturned) == FALSE)
	{
		DWORD dwError = GetLastError();

		if (dwError == ERROR_INSUFFICIENT_BUFFER)
		{
			if (pPrinterInfo != NULL)
			{
				free(pPrinterInfo);
			}

			pPrinterInfo = (PRINTER_INFO_2*)malloc(dwSizeNeeded);
			
			if (pPrinterInfo != NULL)
			{
				dwSize			= dwSizeNeeded;
				dwSizeNeeded	= 0;

				goto lbl_retry;
			}
		}
		else
		{
			if (pPrinterInfo != NULL)
			{
				free(pPrinterInfo);
			}

			_tprintf(TEXT("EnumPrinters failed: %d\r\n"), dwError);

			return bRetVal;
		}
	}
	else
	{
		if (pPrinterInfo != NULL)
		{
			_tprintf(TEXT("Printer Name: %s\r\n"), pPrinterInfo->pPrinterName);
			_tprintf(TEXT("Printer Attr: %d\r\n"), pPrinterInfo->Attributes);

			m_config.setPrinterAttributes(pPrinterInfo->Attributes);
			m_config.setPrinterName(pPrinterInfo->pPrinterName);

			_tprintf(TEXT("Printer state is saved in %s\nRun this tool after Windows reboot to restore the printer state\n"), m_config.m_szConfigFile);

			return m_config.Flush();
		}
		else
		{
			_tprintf(TEXT("None installed printers found.\n"));
		}		
	}

	return bRetVal;
}

/**   Reading previously stored printer attributes and restoring 
	  the printer state

    * @return boolean
*/
bool CPrintersManagement::SetPrinterAttributes()
{
	BOOL				bResult         = FALSE;
	HANDLE              hPrinter        = NULL;
	PRINTER_DEFAULTS    pd              = {0};

	pd.DesiredAccess = PRINTER_ALL_ACCESS;
	bResult			 = OpenPrinter(m_config.getPrinterName(), &hPrinter, &pd);

	if (bResult == FALSE)
	{
		_tprintf(TEXT("OpenPrinter failed %d\r\n"), GetLastError());

		return false;
	}

	PRINTER_INFO_2 * pinfo		= NULL;
	DWORD			dwSize		= 0;
	DWORD			dwNedded	= 0;

lbl_retry:

	if (GetPrinter(hPrinter, 2, (byte*)pinfo, dwSize, &dwNedded) == 0)
	{
		DWORD dw = GetLastError();

		if (dw == ERROR_INSUFFICIENT_BUFFER)
		{
			if (pinfo != NULL)
			{
				free(pinfo);
			}

			pinfo = (PRINTER_INFO_2*)malloc(dwNedded);

			if (pinfo == NULL)
			{
				_tprintf(TEXT("malloc failed with %d for %d\r\n"), GetLastError(), dwNedded);

				return false;
			}

			memset(pinfo, 0, dwNedded);

			dwSize	 = dwNedded;
			dwNedded = 0;

			goto lbl_retry;
		}
	}

	pinfo->Attributes = m_config.getPrinterAttributes(); /// magic printer attributes

	if (!SetPrinter(hPrinter, 2, (byte*)pinfo, 0))
	{
		_tprintf(TEXT("SetPrinter failed %d\r\n"), GetLastError());

		return false;
	}
	
	_tprintf(TEXT("Attributes for %s are set to %d\r\n"), pinfo->pPrinterName, pinfo->Attributes);

	return true;
}